'''
    Manage a channel (private chat too?)
    
    This is the generic, copyable channel object that applies
    generaically to irc clients, not just pypopeye.
'''

import regexes
import modes

class DeadServerError(Exception): pass

class channel(object):
    hooks = []
    nicks = []
    raw = False
    topic = ''
    mode = ''
    
    def __init__(self, server, chan_name, softjoin = 0):
        assert server is not None, 'Server connection is dead!'
        
        self.server_weakref = server
        self.chan_name = chan_name
        
        if softjoin:
        	#Not joining, but check for names and topic
        	print >> server(), 'TOPIC %s\nNAMES %s' % (chan_name, chan_name)
        else:
	        print >> server(), 'JOIN %s' % chan_name
        
        
        #process /NAMES listing, code 353
        self.push_hook(regexes.listing, self._accumulate_nicks)
        #process /TOPIC response, code 332
        self.push_hook(regexes.topic_notice, self._get_topic)
    
    def write(self, data):
        assert self.server_weakref() is not None, 'Server connection is dead!'
        for i in data.split('\n'):
            if not len(i): pass
            print >> self.server_weakref(), 'PRIVMSG %s :%s' % (self.chan_name, i)
        
        
    def part(self, reason, softpart = 0):
        assert self.server_weakref() is not None, 'Server connection is dead!'
        
        serv = self.server_weakref()
        if not softpart:
    	    print >> serv, 'PART %s' % self.chan_name
        serv.channels.remove(self)
        
    def push_hook(self, regex, hook, exclusive = True):
        '''
            Adds a hook to this channel (for commands that need replies)
        '''
        self.hooks.append((regex, hook, exclusive))
        self.setraw()

    def on_raw(self, txt):
        '''
            When the server sends us raw data (because we asked it to)
            see if any of the hooks wants it
        '''
        acted = []
        for i,hook in enumerate(self.hooks):
            regex, function, exclusive = hook
            if regex.match(txt):
                function(txt)
                acted.append(i)
                if exclusive:
                    break
        for i in acted:
            del self.hooks[i]
        if not len(self.hooks):
            self.setraw(False)
        return len(acted)
    
    def _accumulate_nicks(self, data):
        m = regexes.listing.match(data).groupdict()
        if m['code'] == '353':
            names = [i.lstrip('+@~%&') for i in m['names'].split() if i not in self.nicks]
            self.nicks += names
            
            #/NAMES listing not over yet, quasi-recurse until it is
            self.push_hook(regexes.listing, self._accumulate_nicks)
    
    
    def _get_topic(self, data):
        m = regexes.topic_notice.match(data).groupdict()
        self.on_topic(m['topic'])
            
    def setraw(self, on = True):
        self.raw = on
        
    def on_mode(self, setter, mode):
        print '%s sets mode %s %s' % (setter, self.chan_name, mode)
        self.mode = modes.arithmetic(self.mode, mode)
        
    def on_kick(self, nick):
        self.nicks.remove(nick)
        
    def on_nick(self, nick, newnick):
        try:
            i = self.nicks.index(nick)
        except:
            return False
        self.nicks[i] = newnick
        return True

    def on_join(self, nick):
        #Careful - after the preliminary /NAMES listing, you'll still receive
        #a join message with your own name
        if not nick in self.nicks:
            self.nicks.append(nick)
    
    def on_part(self, nick, reason = None):
        try:
            self.nicks.remove(nick)
        except ValueError:
            print 'ERROR REMOVING NICK "%s" FROM %s' % (name, self.chan_name)

    def on_topic(self, topic):
        self.topic = topic
        print 'Topic for %s is now %s' % (self.chan_name, topic)
        return True
    
    def on_quit(self, nick, reason = None):
        try:
            self.nicks.remove(nick)
        except ValueError:
            print 'ERROR REMOVING NICK "%s" FROM %s' % (name, self.chan_name)
